import java.util.Calendar;
import java.util.Date;
import java.util.Vector;

public class EventScheduler {

	private static String className = "EventScheduler: ";
	private static long maxScheduleTime = 24 * 60 * 60 * 1000; // ms
	
	private SunriseSunset sunriseSunset = new SunriseSunset();

	private Vector<ScheduleEvent> scheduleEvents;
	private Vector<ScheduledEvent> scheduledEvents = new Vector<ScheduledEvent>();

	public EventScheduler(Vector<ScheduleEvent> scheduleEvents) {
		this.scheduleEvents = scheduleEvents;
	}

	public Vector<ScheduledEvent> rebuildScheduledEvents() {

		DEBUG("rebuildScheduledEvents " + scheduleEvents.size());

		clearScheduledEvents();

		for (int i = 0; i < scheduleEvents.size(); i++) {

			ScheduleEvent scheduleEvent = scheduleEvents.get(i);

			switch (scheduleEvent.eventType) {

			case TIME_EVENT:
				scheduleTimeEvent(scheduleEvent);
				break;

			case SUN_RISE_EVENT:
				scheduleSunEvent(scheduleEvent);
				break;
				
			case SUN_SET_EVENT:
				scheduleSunEvent(scheduleEvent);
				break;
				
			default:
				DEBUG("No valid event type " + scheduleEvent.eventType);
				break;

			}
		}

		return scheduledEvents;
	}

	private void scheduleTimeEvent(ScheduleEvent scheduleEvent) {
		DEBUG("scheduleTimeEvent");

		Calendar then = getScheduledEventCalendar(scheduleEvent);

		if (then != null) {
			Calendar now = Calendar.getInstance();

			long timeDiff = then.getTimeInMillis() - now.getTimeInMillis();

			if (timeDiff > 0 && timeDiff < maxScheduleTime) {
				addScheduledEvent(scheduleEvent.switchOn, then,
						scheduleEvent.devices);
			}

		}
	}
	
	private void scheduleSunEvent(ScheduleEvent scheduleEvent) {
		DEBUG("scheduleSunEvent " + GeneralSettings.latitude + " " + GeneralSettings.longitude + " " + GeneralSettings.timeZone);
		
		Date sunDate;
		
		if(scheduleEvent.eventType == EventType.SUN_RISE_EVENT) {
			sunDate = sunriseSunset.getSunrise(GeneralSettings.latitude, GeneralSettings.longitude, GeneralSettings.timeZone);
		} 
		else {
			sunDate = sunriseSunset.getSunset(GeneralSettings.latitude, GeneralSettings.longitude, GeneralSettings.timeZone);
		}
		
		scheduleEvent.startHour = (byte)sunDate.getHours();
		scheduleEvent.startMinute = (byte)sunDate.getMinutes();

		Calendar then = getScheduledEventCalendar(scheduleEvent);

		if (then != null) {
			Calendar now = Calendar.getInstance();

			long timeDiff = then.getTimeInMillis() - now.getTimeInMillis();

			if (timeDiff > 0 && timeDiff < maxScheduleTime) {
				DEBUG("ADD " + timeDiff);
				addScheduledEvent(scheduleEvent.switchOn, then,
						scheduleEvent.devices);
			}

		}
	}

	private Calendar getScheduledEventCalendar(ScheduleEvent scheduleEvent) {
		DEBUG("getScheduledEventCalendar");

		Calendar now = Calendar.getInstance();
		Calendar then = Calendar.getInstance();
		then.set(then.get(Calendar.YEAR), then.get(Calendar.MONTH),
				then.get(Calendar.DATE), scheduleEvent.startHour,
				scheduleEvent.startMinute, 0);

		long timeDiff = then.getTimeInMillis() - now.getTimeInMillis();
		int dayOfWeek = now.get(Calendar.DAY_OF_WEEK);

		if (timeDiff < 0) {
			dayOfWeek = (dayOfWeek + 1) % (Calendar.SATURDAY + 1); //Saturday = 7
			then.setTimeInMillis(then.getTimeInMillis() + 24 * 60 * 60 * 1000);
		}

		if (Macros.getWeekday(Calendar.MONDAY, scheduleEvent.weekdays)
				&& dayOfWeek == Calendar.MONDAY) {
			return then;
		}

		if (Macros.getWeekday(Calendar.TUESDAY, scheduleEvent.weekdays)
				&& dayOfWeek == Calendar.TUESDAY) {
			return then;
		}

		if (Macros.getWeekday(Calendar.WEDNESDAY, scheduleEvent.weekdays)
				&& dayOfWeek == Calendar.WEDNESDAY) {
			return then;
		}

		if (Macros.getWeekday(Calendar.THURSDAY, scheduleEvent.weekdays)
				&& dayOfWeek == Calendar.THURSDAY) {
			return then;
		}

		if (Macros.getWeekday(Calendar.FRIDAY, scheduleEvent.weekdays)
				&& dayOfWeek == Calendar.FRIDAY) {
			return then;
		}

		if (Macros.getWeekday(Calendar.SATURDAY, scheduleEvent.weekdays)
				&& dayOfWeek == Calendar.SATURDAY) {
			return then;
		}

		if (Macros.getWeekday(Calendar.SUNDAY, scheduleEvent.weekdays)
				&& dayOfWeek == Calendar.SUNDAY) {
			return then;
		}

		return null;
	}

	public void addScheduledEvent(boolean switchOn, Calendar startTime,
			long devices) {
		DEBUG("addScheduledEvent " + scheduledEvents.size());

		ScheduledEvent scheduledEvent = new ScheduledEvent(switchOn, startTime,
				devices);
		scheduledEvents.add(scheduledEvent);

		DEBUG("addScheduledEvent " + scheduledEvents.size());
	}

	public void clearScheduledEvents() {
		DEBUG("clearScheduledEvents");

		scheduledEvents.clear();
	}

	private static void DEBUG(String debugString) {
		Macros.DEBUG(className + debugString);
	}

}
